package com.bifang.module.file.core.util;

import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.crypto.SmUtil;
import com.bifang.engine.assistant.core.enums.BoolEnum;
import com.bifang.engine.assistant.core.exception.AppException;
import com.bifang.module.base.common.util.SignUtil;
import com.bifang.module.base.common.vo.application.ApplicationKeyVO;
import com.bifang.module.base.common.vo.application.ApplicationVO;
import com.bifang.module.base.core.integration.ApplicationIntegration;
import com.bifang.module.file.common.vo.FileClassVO;
import com.bifang.module.file.common.vo.FileInfoVO;
import com.bifang.module.file.common.util.FileDiffUtil;
import com.bifang.module.file.core.biz.FileClassIntegration;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

@Component
public class FileCommonUtil {
    protected Logger logger = LoggerFactory.getLogger(this.getClass());
    @Value("${system.config.api.check.sign:true}")
    private Boolean signFlag;
    @Value("${spring.servlet.multipart.location}")
    private String tmpPath;
    @Autowired
    private ApplicationIntegration applicationIntegration;
    @Autowired
    private FileClassIntegration fileClassIntegration;

    /** 生成文件路径 */
    public String getPath(String path, String str) {
        if (StringUtils.isBlank(path)) {
            return str;
        }
        if (str.startsWith("\\")) {
            str = str.substring(2);
        } else if (str.startsWith("/")) {
            str = str.substring(1);
        }
        if (path.endsWith("\\") || path.endsWith("/")) {
            path = path + str;
        } else {
            if (path.indexOf("\\") > 0) {
                path = path + "\\" + str;
            } else {
                path = path + "/" + str;
            }
        }
        return path;
    }

    /** 获取临时文件 */
    public File createTempFile(InputStream in, String fileName) {
        // 如果要加密，先生成本地临时文件
        String path = tmpPath;
        path = getPath(path, fileName);
        File file = null;
        try {
            file = FileUtil.writeFromStream(in, path);
        } catch (Exception e) {
            throw new AppException("生成临时文件失败：" + e.getMessage());
        }
        return file;
    }

    /** 获取临时文件 空文件 */
    public File createTempFile(String fileName) {
        String path = tmpPath;
        path = this.getPath(path, fileName);
        if (FileUtil.exist(path)) {
            return FileUtil.file(path);
        }
        return FileUtil.touch(path);
    }

    public File createTempFileDownload(String fileName) {
        String path = tmpPath;
        path = this.getPath(path, "download");
        path = this.getPath(path, fileName);
        if (FileUtil.exist(path)) {
            return FileUtil.file(path);
        }
        return FileUtil.touch(path);
    }

    /** 获取临时文件 */
    public File createTempFile(String src, String fileName) {
        // 如果要加密，先生成本地临时文件
        String path = tmpPath;
        path = this.getPath(path, fileName);
        File file = null;
        if (FileUtil.exist(path)) {
            return FileUtil.file(path);
        }
        try {
            file = FileUtil.copy(src, path, true);
        } catch (Exception e) {
            throw new AppException("生成临时文件失败：" + e.getMessage());
        }
        return file;
    }

    /** 获取临时文件 */
    public File createTempFileDownload(String src, String fileName) {
        // 如果要加密，先生成本地临时文件
        String path = tmpPath;
        path = this.getPath(path, "download");
        path = this.getPath(path, fileName);
        File file = null;
        if (FileUtil.exist(path)) {
            return FileUtil.file(path);
        }
        try {
            file = FileUtil.copy(src, path, true);
        } catch (Exception e) {
            throw new AppException("生成临时文件失败：" + e.getMessage());
        }
        return file;
    }

    /** 删除临时文件 */
    public void delTempFile(File file) {
        try {
            FileUtil.del(file);
        } catch (Exception e) {
            logger.error("删除临时文件异常：", e);
        }
    }

    /** 删除临时文件 */
    public void delTempFileDownloadByName(String fileName) {
        String path = tmpPath;
        path = this.getPath(path, "download");
        path = this.getPath(path, fileName);
        try {
            if (FileUtil.exist(path)) {
                FileUtil.del(path);
            }
        } catch (Exception e) {
            logger.error("删除临时文件异常：", e);
        }
    }

    /** 删除临时文件 */
    public void delTempFileByName(String fileName) {
        String path = tmpPath;
        path = this.getPath(path, fileName);
        try {
            if (FileUtil.exist(path)) {
                FileUtil.del(path);
            }
        } catch (Exception e) {
            logger.error("删除临时文件异常：", e);
        }
    }

    /** 删除临时文件 */
    public void delTempFile(String path) {
        try {
            FileUtil.del(path);
        } catch (Exception e) {
            logger.error("删除临时文件异常：", e);
        }
    }

    /** 初始化设置文件信息 */
    public void initFile(File file, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        String fileMd5 = fileInfoVO.getFileMd5();
        if (StringUtils.isBlank(fileMd5)) {
            fileMd5 = FileDiffUtil.getMD5(file);
        }
        if (StringUtils.isBlank(fileInfoVO.getFileName())) {
            fileInfoVO.setFileName(file.getName());
        }
        if (StringUtils.isBlank(fileInfoVO.getFileSuffix())) {
            fileInfoVO.setFileSuffix(FileTypeUtil.getType(file));
        }
        if (fileInfoVO.getFileSize() == null) {
            fileInfoVO.setFileSize(file.length());
        }
        this.setInitFile(fileMd5, fileClassVO, fileInfoVO);
    }

    /** 初始化设置文件信息 */
    public void initFile(MultipartFile file, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        String fileMd5 = fileInfoVO.getFileMd5();
        if (StringUtils.isBlank(fileMd5)) {
            fileMd5 = FileDiffUtil.getMD5(file);
        }
        if (StringUtils.isBlank(fileInfoVO.getFileName())) {
            fileInfoVO.setFileName(file.getName());
        }
        if (StringUtils.isBlank(fileInfoVO.getFileSuffix())) {
            try {
                fileInfoVO.setFileSuffix(FileTypeUtil.getType(file.getInputStream()));
            } catch (IOException e) {
                logger.error("获取文件大小失败", e);
            }
        }
        if (fileInfoVO.getFileSize() == null) {
            fileInfoVO.setFileSize(file.getSize());
        }
        this.setInitFile(fileMd5, fileClassVO, fileInfoVO);
    }

    /** 初始化设置文件信息 */
    public void initFile(InputStream in, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        String fileMd5 = fileInfoVO.getFileMd5();
        if (StringUtils.isBlank(fileMd5)) {
            fileMd5 = FileDiffUtil.getMD5(in);
        }
        if (StringUtils.isBlank(fileInfoVO.getFileSuffix())) {
            fileInfoVO.setFileSuffix(FileTypeUtil.getType(in));
        }
        this.setInitFile(fileMd5, fileClassVO, fileInfoVO);
    }

    private void setInitFile(String fileMd5, FileClassVO fileClassVO, FileInfoVO fileInfoVO) {
        fileInfoVO.setFileMd5(fileMd5);
        String fileName = fileMd5 + "." + fileInfoVO.getFileSuffix();
        if (StringUtils.isBlank(fileInfoVO.getFileName())) {
            fileInfoVO.setFileName(fileName);
        }
        String path = this.getPath(fileClassVO.getFileClassPath(), fileName);
        fileInfoVO.setFilePath(path);
    }

    /** 判断是否为允许的上传文件类型,true表示允许 */
    public void checkFile(String suffix, Long size, FileClassVO fileClassVO) {
        String suffixList = fileClassVO.getFileType();
        if (StringUtils.isNotBlank(suffixList)) {
            // 设置允许上传文件类型
            if (!suffixList.contains(suffix.trim().toLowerCase())) {
                throw new AppException(suffix + "类型文件不能上传");
            }
        }
        if (fileClassVO.getMaxSize() != null) {
            if (fileClassVO.getMaxSize() != 0 && size != null) {
                if (size > fileClassVO.getMaxSize()) {
                    throw new AppException(
                            "文件大小超过上限(" + comSize(fileClassVO.getMaxSize()) + ")，不能上传");
                }
            }
        }
    }

    private String comSize(Long size) {
        return (int) ((size / 1024) + 1) + "KB";
    }

    /** 校验base64文件获取大小控制 */
    public void checkBase64(Long length) {
        if (((length / 1024) / 1024) > 10) {
            throw new AppException("文件大于10M不能用base64方式获取，请用下载");
        }
    }

    public String getPath(String fileBasePath, String fileClassPath, String fileName) {
        String path = "";
        if (StringUtils.isNotBlank(fileBasePath)) {
            path = fileBasePath;
        }
        if (StringUtils.isNotBlank(fileClassPath)) {
            path = getPath(path, fileClassPath);
        }
        if (StringUtils.isNotBlank(fileName)) {
            path = getPath(path, fileName);
        }
        return path;
    }
    /***
     * 校验签名
     * */
    public void checkSign(String appId,String signature,String timestamp,String fileClassCode){
        if (!signFlag){
            return;
        }
        if (StringUtils.isBlank(appId)){
            throw new AppException("应用不能为空");
        }
        ApplicationKeyVO applicationKeyVO=new ApplicationKeyVO();
        applicationKeyVO.setAppId(Long.parseLong(appId));
        ApplicationVO applicationVO=applicationIntegration.getById(applicationKeyVO);
        String secret=applicationVO.getAppSecret();
        if (BoolEnum.FALSE.getType().equalsIgnoreCase(applicationVO.getSignFlag())){
            //应用设置了不需要签名，直接返回
            return;
        }
        if (StringUtils.isBlank(secret)){
            throw new AppException("应用秘钥未配置");
        }
        if (StringUtils.isBlank(fileClassCode)){
            throw new AppException("文件分类不能空");
        }
        FileClassVO fileClassVO=fileClassIntegration.getFileClassDetail(fileClassCode);
        if (BoolEnum.FALSE.getType().equalsIgnoreCase(fileClassVO.getSignFlag())){
            //文件分类中设置了不需要签名，直接返回
            return;
        }
        if (StringUtils.isBlank(signature)){
            throw new AppException("签名无效");
        }
        if (StringUtils.isBlank(timestamp)){
            throw new AppException("请求过期");
        }
        if(!SignUtil.verifyTimestamp(Long.parseLong(timestamp))){
            throw new AppException("请求过期！请检查服务器时间");
        }

        String str ="appId=" + appId+"&secret=" + secret + "&timestamp=" + timestamp;
        //签名使用appId+appKey+appSecret+时间戳的国密sm3,转大写
        String sign = SmUtil.sm3(str).toUpperCase();
        if (!sign.equals(signature)) {
            throw new AppException("签名无效");
        }
    }
}
